from ctaf_core.ctaf_factory import CtafFactory
from ctaf_core.bus_client_bundle.bus_client_bundle import BusClientBundle
from ctaf_core.bus_server_bundle.bus_server_bundle import BusServerBundle
from ctaf_core.ctaf_objects.base_biz_app import BaseBizApp
from ctaf_core.ctaf_objects.base_bundle import BaseBundle
from typing import Dict, Type

from ctaf_core.ctaf_objects.base_event import MsgEvent, BaseEvent
from ctaf_core.ctaf_objects.ctaf_general_types import EventHandlerType
from ctaf_core.ctaf_utils.local_service_call_util import LocalServiceCallUitl
from ctaf_core.data_access_bundle.data_access_bundle import DataAccessBundle
from ctaf_core.event_driven_bundle.event_driven_bundle import EventDrivenBundle
from ctaf_core.ctaf_resources.ctaf_settings import CTAFsettings
from ctaf_core.ctaf_objects.base_exception import CTAFbaseException
from ctaf_core.log_trace_bundle.log_trace_bundle import LogTraceBundle
from ctaf_core.log_trace_bundle.logging import LogRecorder, LoggerFactory
from ctaf_core.quartz_task_bundle.quartz_task_bundle import QuartzTaskBundle
from ctaf_facade.enumerations.error_code_enum import ErrorCodeEnum
from ctaf_facade.enumerations.event_handler_exe_type_num import EventHandlerExeTypeEnum
from ctaf_facade.enumerations.event_type_enum import EventTypeEnum


class CoreTradeAppFramework(CtafFactory):
    log_recorder: LogRecorder = LoggerFactory.get_logger()

    def __init__(self, ctaf_general_setting_filename: str):
        """"""
        if CtafFactory.ctaf_instance:
            return

        CTAFsettings.load_setting(ctaf_general_setting_filename)
        self.__bundles: Dict[str, BaseBundle] = {}
        self.__apps: Dict[str, BaseBizApp] = {}

        self.__init_bundles()
        CtafFactory.ctaf_instance = self

        LocalServiceCallUitl.init_local_service_container(CTAFsettings.get_setting("localServiceServerSettingFilename"))

    def __init_bundles(self):
        bundle_names: [] =  CTAFsettings.get_setting("load.bundles")
        CoreTradeAppFramework.log_recorder.write_info_log("Bundles to be initialized: " + str(bundle_names))
        self.__add_ctaf_bundles(bundle_names)

    def __add_ctaf_bundles(self, bundle_names: []):
        for name in bundle_names:
            if name == "LogTraceBundle":
                self.__bundles["LogTraceBundle"] = LogTraceBundle()
                CoreTradeAppFramework.log_recorder.write_info_log(name + " has been initialized!")
                continue
            if name == "EventDrivenBundle":
                self.__bundles["EventDrivenBundle"] = EventDrivenBundle()
                CoreTradeAppFramework.log_recorder.write_info_log(name + " has been initialized!")
                continue
            if name == "BusServerBundle":
                self.__bundles["BusServerBundle"] = BusServerBundle()
                CoreTradeAppFramework.log_recorder.write_info_log(name + " has been initialized!")
                continue
            if name == "BusClientBundle":
                self.__bundles["BusClientBundle"] = BusClientBundle()
                CoreTradeAppFramework.log_recorder.write_info_log(name + " has been initialized!")
                continue
            if name == "QuartzTaskBundle":
                self.__bundles["QuartzTaskBundle"] = QuartzTaskBundle()
                CoreTradeAppFramework.log_recorder.write_info_log(name + " has been initialized!")
                continue
            if name == "DataAccessBundle":
                self.__bundles["DataAccessBundle"] = DataAccessBundle()
                CoreTradeAppFramework.log_recorder.write_info_log(name + " has been initialized!")
                continue
            else:
                CoreTradeAppFramework.log_recorder.write_info_log("Invalid bundle name: "+name)
                raise CTAFbaseException(ErrorCodeEnum.BOOT_CTAF_ERROR,"Invalid bundle name")

    def get_bundle_by_name(self, bundle_name: str)-> BaseBundle:
        return self.__bundles.get(bundle_name)

    def get_biz_app_by_name(self, biz_app_name: str)-> BaseBizApp:
        return self.__apps.get(biz_app_name)

    def boot_ctaf(self):
        for bundle_name, bundle in self.__bundles.items():
            if bundle_name == "BusClientBundle":
                if isinstance(bundle, BusClientBundle):
                    bundle.reg_recv_msg_handler(self.__bus_client_msg_callback)
                    bundle.load_bundle()
                    CoreTradeAppFramework.log_recorder.write_info_log("Bundle has been loaded: " + bundle_name)
                continue
            if bundle_name == "BusServerBundle":
                if isinstance(bundle, BusServerBundle):
                    self.reg_event_handler(bundle.publish_msg, None,  EventHandlerExeTypeEnum.ASYNC_IO_HANDLER)
                    bundle.load_bundle()
                    CoreTradeAppFramework.log_recorder.write_info_log("Bundle has been loaded: " + bundle_name)
                continue
            else:
                bundle.load_bundle()
                CoreTradeAppFramework.log_recorder.write_info_log("Bundle has been loaded: " + bundle_name)

    def __bus_client_msg_callback(self, msg_event: MsgEvent)-> None:
        event_driven_bundle = self.__bundles["EventDrivenBundle"]
        if isinstance(event_driven_bundle, EventDrivenBundle):
            event_driven_bundle.put_event(msg_event)

    def add_biz_app(self, biz_app_class: Type[BaseBizApp], biz_app_name: str = None):

        if not biz_app_name:
            biz_app: BaseBizApp = biz_app_class()
            biz_app_name= biz_app.get_app_name()
        else:
            biz_app: BaseBizApp = biz_app_class(self, biz_app_name)
        self.__apps[biz_app_name] = biz_app
        CoreTradeAppFramework.log_recorder.write_info_log(biz_app_name + " has been added!")

    def pub_event(self, base_event: BaseEvent):
        bundle = self.get_bundle_by_name("EventDrivenBundle")
        if isinstance(bundle, EventDrivenBundle):
            return bundle.put_event(base_event)

    def reg_event_handler (self, handler:EventHandlerType, event_type:EventTypeEnum = None,execution_type: EventHandlerExeTypeEnum = EventHandlerExeTypeEnum.SYNC_HANDLER):
        bundle = self.get_bundle_by_name("EventDrivenBundle")
        if isinstance(bundle, EventDrivenBundle):
            return bundle.event_handler_register(handler, event_type,execution_type)

    def dereg_event_handler (self, handler:EventHandlerType, event_type:EventTypeEnum = None,execution_type: EventHandlerExeTypeEnum = EventHandlerExeTypeEnum.SYNC_HANDLER):
        bundle = self.get_bundle_by_name("EventDrivenBundle")
        if isinstance(bundle, EventDrivenBundle):
            return bundle.event_handler_unregister(handler, event_type, execution_type)

    def log_debug(self, msg: str = None, exception: CTAFbaseException = None):
        bundle = self.get_bundle_by_name("LogTraceBundle")
        if isinstance(bundle, LogTraceBundle):
            return bundle.debug(msg, exception)

    def log_info(self, msg: str = None, exception: CTAFbaseException = None):
        bundle = self.get_bundle_by_name("LogTraceBundle")
        if isinstance(bundle, LogTraceBundle):
            return bundle.info(msg, exception)

    def log_warn(self, msg: str = None, exception: CTAFbaseException = None):
        bundle = self.get_bundle_by_name("LogTraceBundle")
        if isinstance(bundle, LogTraceBundle):
            return bundle.warn(msg, exception)

    def log_error(self, msg: str = None, exception: CTAFbaseException = None):
        bundle = self.get_bundle_by_name("LogTraceBundle")
        if isinstance(bundle, LogTraceBundle):
            return bundle.error(msg, exception)

    def stop_ctaf(self):
        for bundle_name, bundle in self.__bundles.items():
            CoreTradeAppFramework.log_recorder.write_info_log(bundle_name + " start unloading!")
            bundle.unload_bundle()
            CoreTradeAppFramework.log_recorder.write_info_log(bundle_name + " has been unloaded!")

